#ifndef TRACEWIDGET_H
#define TRACEWIDGET_H

#include <QWidget>

#include "UVMGlobal.h"
#include "VMPBridge.h"

#define VMPSTUDIO_PORT 30332

typedef std::map<duint, std::vector<arm_subregs_t>> RecordARM;
typedef std::map<duint, std::vector<arm64_subregs_t>> RecordARM64;

class QVBoxLayout;
class CPUWidget;
class TraceRegisters;
class TraceBrowser;
class TraceFileReader;
class StdTable;
class LogView;

namespace Ui {
class TraceWidget;
}

class UVMTraceWidget : public QWidget {
  Q_OBJECT

 public:
  explicit UVMTraceWidget(QWidget* parent);
  ~UVMTraceWidget();

  TraceBrowser* getTraceBrowser();
  void addLog(const QString& msg) { addLogSlot(msg.toUtf8()); }
  QString uvmShell(const QString& cmds, bool result, bool timeout);
  int uvmSend(UVMSVR_CommandType type, const char* buf, size_t bufsz,
              uint64_t extra = 0) {
    mUVMClient.send(type, buf, bufsz, extra);
  }

  void uvmTraceStart(const VMPManaFunc &fn);
  void uvmTraceStop(const VMPManaFunc &fn);

  bool isAttached() {
    return m_rtbase != 0;
  }

  void detach();

  std::string mUVMTriple;
  UVMClient mUVMClient;
  UraniumVMServer mUVMServer;

 protected slots:
  void traceSelectionChanged(unsigned long long selection);
  void updateSlot();
  void addLogSlot(QByteArray msg);

 protected:
  TraceBrowser* mTraceWidget;
  TraceRegisters* mGeneralRegs;
  LogView* mInfo;
  StdTable* mOverview;

  QProcess m_fridasvr;

  uint64_t m_rtbase = 0;
  RecordARM m_recordARM;
  RecordARM64 m_recordARM64;

  void updateInfobox(unsigned long long selection, TraceFileReader* traceFile,
                     const REGDUMP* registers);
  void setupUVMServer();
  void parseUVMProtocol(UVMDBG_CommandType type, const char *buf, int bufsz, uint64_t extra);
  void setBp(const VMPManaFunc &fn, bool set);

  template <typename RECORD,  typename HDR, typename SUBREGS>
  void updateRecord(RECORD *record, const char *buf, int bufsz);

 private:
  Ui::TraceWidget* ui;
};

extern UVMTraceWidget *uvmWin;

#endif  // TRACEWIDGET_H
